/******************************************************************************
*
* This file is part of FreeTrack (http://code.google.com/p/qtfreetrack).
* BY Willy Gardiol (willy@gardiol.org)
*
* FreeTrack is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FreeTrack is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Foobar.  If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/

#include "workersavegpx.h"
#include "gps_waypoint.h"

WorkerSaveGpx::WorkerSaveGpx(const QString& filename,
                             const GPS_track* t,
                             const QString& ti) :
    WorkerProcess(2,ti),
    file(filename),
    writer(NULL)
{
    initialize(t);
    if ( file.open( QIODevice::WriteOnly ) )
            writer = new QXmlStreamWriter( &file );
}

WorkerSaveGpx::WorkerSaveGpx(QByteArray& b,
                             const GPS_track* t,
                             const QString& ti) :
    WorkerProcess(1, ti),
    writer(NULL)
{
    writer = new QXmlStreamWriter( &b );
    initialize(t);
}

void WorkerSaveGpx::initialize(const GPS_track* t)
{
    track = t;
    n_points = n_waypoints = 0;
    QList<int> listLegs = track->listLegs();

    tot_points = tot_waypoints = 0;
    foreach (int leg_id, listLegs)
    {
        const GPS_leg* leg = track->leg( leg_id );
        if (leg != NULL )
            tot_points += leg->nPoints();
    }
    tot_waypoints = track->listWaypoints().count();
    setMinMaxProgress( tot_waypoints + tot_points );
}

WorkerSaveGpx::~WorkerSaveGpx()
{
    if ( writer != NULL )
        delete writer;
}

bool WorkerSaveGpx::updateWaypoints()
{
    updateText(0, tr("Saved %1/%2 waypoints.").arg(n_waypoints)
                                              .arg(tot_waypoints) );
    updateProgress( n_waypoints + n_points );
    return please_terminate;
}

bool WorkerSaveGpx::updatePoints()
{
    updateText(1, tr("Saved %1/%2 points.").arg(n_points)
                                           .arg(tot_points));
    updateProgress( n_waypoints + n_points );
    return please_terminate;
}

bool WorkerSaveGpx::do_stuff()
{
    if ( writer == NULL )
    {
        setErrorString( tr("Invalid destination!" ) );
        return false;
    }

    updateWaypoints();
    updatePoints();

    // Write headers...
    writer->setAutoFormatting(true);
    writer->writeStartDocument();

    writer->writeStartElement("gpx");
    writer->writeAttribute("version", "1.1");
    writer->writeAttribute("creator", "Track@Way "VERSION );
    writer->writeAttribute("xmlns", "http://www.topografix.com/GPX/1/1");


    // Write metadata...

    writer->writeStartElement("metadata");
    writer->writeTextElement("name", track->title() );
    writer->writeTextElement("desc", track->description() );
    writer->writeEmptyElement("bounds");
    QRectF bounds = track->boundingRect().normalized();
    writer->writeAttribute("minlat", QString("%1").arg(bounds.top(), 0, 'f'));
    writer->writeAttribute("minlon", QString("%1").arg(bounds.left(), 0, 'f'));
    writer->writeAttribute("maxlat", QString("%1").arg(bounds.bottom(), 0, 'f'));
    writer->writeAttribute("maxlon", QString("%1").arg(bounds.right(), 0, 'f'));
    writer->writeEndElement();

    // Save all waypoints...
    foreach (int wp_id, track->listWaypoints() )
    {
        const GPS_waypoint* wp = track->waypoint( wp_id );
        if ( wp != NULL )
        {
            writeWaypoint(wp);
        }
        updateWaypoints();
        if ( please_terminate )
            return false;
    }

    // Iterate all legs...
    foreach (int leg_id, track->listLegs() )
    {
        const GPS_leg* leg = track->leg( leg_id );
        if ( leg != NULL )
        {
            writeLeg(leg);
        }
        if ( please_terminate )
            return false;
    }

    writer->writeEndElement(); // gpx
    writer->writeEndDocument();

    return true;
}

void WorkerSaveGpx::writeLeg(const GPS_leg* leg)
{
    writer->writeStartElement("trk");

    writer->writeTextElement("name", leg->title() );

    writer->writeStartElement("trkseg");
    for ( int i = 0; i < leg->nPoints(); i++ )
    {
        const GPS_point* pt = leg->point(i);
        writer->writeStartElement("trkpt");
        writer->writeAttribute("lat", QString("%1").arg(pt->latitude(), 0, 'f') );
        writer->writeAttribute("lon", QString("%1").arg(pt->longitude(), 0, 'f') );

        writer->writeTextElement("ele", QString("%1").arg(pt->altitude(), 0, 'f') );
        writer->writeTextElement("time", pt->timestamp().toString( Qt::ISODate ) );
        writer->writeTextElement("magvar", QString("%1").arg(pt->magneticVariation(), 0, 'f') );
        GPS_dop dop = pt->dop();
        if ( dop.hdop() > -1 )
            writer->writeTextElement("hdop", QString("%1").arg(dop.hdop()) );
        if ( dop.vdop() > -1 )
            writer->writeTextElement("vdop", QString("%1").arg(dop.vdop()) );
        if ( dop.pdop() > -1 )
            writer->writeTextElement("pdop", QString("%1").arg(dop.pdop()) );

        writer->writeStartElement( "extensions" );
        writer->writeTextElement("speed", QString("%1").arg(pt->speed(), 0, 'f') );
        writer->writeTextElement("trackaway_direction", QString("%1").arg( pt->direction(), 0, 'f', 2) );
        writer->writeTextElement("trackaway_steepness", QString("%1").arg( pt->steepness(), 0, 'f', 2 ) );
        writer->writeEmptyElement( "trackaway_precision" );
        writer->writeAttribute("h_precision", QString("%1").arg(pt->h_precision()) );
        writer->writeAttribute("v_precision", QString("%1").arg(pt->v_precision()) );
        writer->writeEndElement(); // extensions

        writer->writeEndElement(); // wpt
        n_points++;
        updatePoints();
        if ( please_terminate )
            return;
    }

    writer->writeEndElement(); // trkseg

    writer->writeStartElement( "extensions" );
    writer->writeEmptyElement( "trackaway_color" );
    QColor color = leg->color();
    writer->writeAttribute("r", QString("%1").arg(color.red()) );
    writer->writeAttribute("g", QString("%1").arg(color.green()) );
    writer->writeAttribute("b", QString("%1").arg(color.blue()) );
    writer->writeEndElement(); // extensions

    writer->writeEndElement(); // trk
}

void WorkerSaveGpx::writeWaypoint(const GPS_waypoint * wp )
{
    writer->writeStartElement("wpt");
    writer->writeAttribute("lat", QString("%1").arg(wp->latitude(), 0, 'f'));
    writer->writeAttribute("lon", QString("%1").arg(wp->longitude(), 0, 'f'));

    writer->writeTextElement("ele", QString("%1").arg(wp->altitude()));
    writer->writeTextElement("name", wp->name() );
    writer->writeTextElement("desc", wp->description() );

    writer->writeStartElement( "extensions" );
    writer->writeEmptyElement( "trackaway_color" );
    QColor color = wp->color();
    writer->writeAttribute("r", QString("%1").arg(color.red()) );
    writer->writeAttribute("g", QString("%1").arg(color.green()) );
    writer->writeAttribute("b", QString("%1").arg(color.blue()) );
    writer->writeEndElement(); // extensions

    writer->writeEndElement(); // wpt

    n_waypoints++;
}
